package com.avo.ramcache.orm.impl;

import com.avo.ramcache.orm.impl.m2s.ServerHibernateTemplate;
import com.avo.ramcache.orm.Querier;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate5.HibernateCallback;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import java.util.List;

@SuppressWarnings("unchecked")
public class HibernateQuerier extends HibernateDaoSupport implements Querier {

    public HibernateQuerier() {

    }

    public HibernateQuerier(SessionFactory sessionFactory) {
        super();
        setSessionFactory(sessionFactory);
    }

    @Override
    public <T> List<T> all(Class<T> clz) {
        return getHibernateTemplate().loadAll(clz);
    }

    @Override
    public <T> List<T> allByServer(int server, Class<T> clz) {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(clz);
        return (List<T>) getHibernateTemplate().findByCriteria(detachedCriteria);
    }

    @Override
    public <T> List<T> listAll(Class<T> clz, String queryname, Object... params) {
        return (List<T>) getHibernateTemplate().findByNamedQuery(queryname, params);
    }

    @Override
    public <T> List<T> listCommon(Class<T> clz, String queryname, Object... params) {
        return (List<T>) getHibernateTemplate().findByNamedQuery(queryname, params);
    }

    @Override
    public <T> List<T> listByServer(int server, Class<T> clz, String queryname, Object[] querynameParams) {
        ServerHibernateTemplate hibernateTemplate = (ServerHibernateTemplate) getHibernateTemplate();
        return hibernateTemplate.S2SListByServer(server, clz, queryname, querynameParams);
    }

    @Override
    public <T> List<T> listByServerWithLimit(int server, int limit, Class<T> clz, String queryname, Object[] querynameParams) {
        ServerHibernateTemplate hibernateTemplate = (ServerHibernateTemplate) getHibernateTemplate();
        return hibernateTemplate.S2SListByServer(server, clz, 1, limit, queryname, querynameParams);
    }

    @Override
    public <T> T unique(Class<T> clz, String queryname, Object... params) {
        return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<T>() {
            @Override
            public T doInHibernate(Session session) throws HibernateException {
                Query query = session.getNamedQuery(queryname);
                for (int i = 0; i < params.length; i++) {
                    query.setParameter(i, params[i]);
                }
                return (T) query.uniqueResult();
            }
        });
    }

    @Override
    public <T> T unique(int server, Class<T> clz, String queryname, Object... params) {
        throw new RuntimeException("s2s can not support this method");
    }

    @Override
    protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
        return new ServerHibernateTemplate(sessionFactory);
    }

    @Override
    public void executeByServer(int server, String queryname, Object[] params) {
        getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Integer>() {
            @Override
            public Integer doInHibernate(Session session) throws HibernateException {
                Query query = session.getNamedQuery(queryname);
                return query.executeUpdate();
            }
        });
    }
}
